--[[ 编码: WMS-20-26 名称: 入库空料箱计算 作者:HAN 日期:2025-1-29 级别:项目 函数: RunEmptyBoxOutProcess 功能: -- 后台脚本计算入库需要呼出多少空料箱 更改记录: V3.0 HAN 20241231 改成后台线程来处理空料箱呼出计算,因为这个过程是一个比较长的事务,有并发锁表的风险 本次改进的目的就是将这些长事务统一交给后台一个线程排队处理 --]] wms_pac = require ("wms_pac_cbg") -- 空料箱预先分配算法 -- 生成波次入库明细 -- strIONo 入库单号 -- wave_detail [{item_name,item_code,qty,weight,volume,cell_type}] local function generate_wave_detail( strLuaDEID, strIONo, wave_detail ) local nRet, strRetInfo local strCondition local data_objs strCondition = "S_IO_NO = '"..strIONo.."'" nRet, data_objs = m3.QueryDataObject(strLuaDEID, "Inbound_Detail", strCondition, "N_ROW_NO" ) if (nRet ~= 0) then return 2, "QueryDataObject失败!"..data_objs end if ( data_objs == '' ) then return 0 end local n, item_code, qty, weight, volume local detail_attrs local bFind for n = 1, #data_objs do detail_attrs = m3.KeyValueAttrsToObjAttr(data_objs[n].attrs) item_code = lua.Get_StrAttrValue( detail_attrs.S_ITEM_CODE ) qty = lua.StrToNumber( detail_attrs.F_QTY ) weight = lua.StrToNumber( detail_attrs.F_WEIGHT ) volume = lua.StrToNumber( detail_attrs.F_VOLUME ) if ( item_code ~= '' and qty > 0 ) then bFind = false for m = 1, #wave_detail do if (wave_detail[m].item_code == item_code) then bFind = true wave_detail[m].qty = wave_detail[m].qty + qty break end end if ( bFind == false ) then local wave_item = { item_code = item_code, item_name = lua.Get_StrAttrValue( detail_attrs.S_ITEM_NAME ), qty = qty, weight = weight, volume = volume, cell_type = lua.Get_StrAttrValue( detail_attrs.S_CELL_TYPE ) } table.insert( wave_detail, wave_item ) end end end return 0 end -- 返回结果 result = { cntr_count = 2, wave_obj_id = "", cntr_cell_list = {}} --[[ datajson 格式: paramter = { station = station, login = strUserLogin, user_name = strUserName, data_json = data_json } ]] function RunEmptyBoxOutProcess ( strLuaDEID ) local nRet, strRetInfo, n local paramter, data_json local result = { cntr_count = 0 } m3.PrintLuaDEInfo( strLuaDEID ) nRet, paramter = m3.GetSysDataJson( strLuaDEID ) if (nRet ~= 0) then lua.Error( strLuaDEID, debug.getinfo(1), data_json ) end data_json = paramter.data_json nCount = #data_json if ( nCount == 0 ) then result = { cntr_count = 0 } mobox.returnValue( strLuaDEID, 1, lua.table2str(result) ) return 0 end -- 从入库单这里获取 仓库、库区编码,如果不一样报错 local station = lua.Get_StrAttrValue( paramter.station ) local wh_code = '' local area_code = '' local compose = {} local obj_attrs, strCondition local wave_detail_list = {} local inbound_order for n = 1, nCount do obj_attrs = m3.KeyValueAttrsToObjAttr( data_json[n].attrs ) -- 判断一下入库单是否有安排了波次,如果有就终止程序 strCondition = "S_ID = '"..lua.trim_guid_str( data_json[n].id ).."'" nRet, inbound_order = m3.GetDataObjByCondition(strLuaDEID, "Inbound_Order", strCondition ) if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), inbound_order ) end if ( lua.Get_StrAttrValue( inbound_order.wave_no ) ~= '' ) then mobox.stopProgram( strLuaDEID, "入库单'"..inbound_order.no.."'已经有入库波次,波次号 = '"..inbound_order.wave_no.."'" ) return 1 end local item = m3.AllocObject(strLuaDEID,"IW_Compose") item.po_no = obj_attrs.S_NO item.wave_no = '' if ( wh_code == '' ) then wh_code = lua.Get_StrAttrValue( obj_attrs.S_WH_CODE ) else if ( wh_code ~= obj_attrs.S_WH_CODE ) then mobox.stopProgram( strLuaDEID, "选中的入库单仓库必须是一样的!" ) return 1 end end if ( area_code == '' ) then area_code = lua.Get_StrAttrValue( obj_attrs.S_AREA_CODE ) else if ( area_code ~= obj_attrs.S_AREA_CODE ) then mobox.stopProgram( strLuaDEID, "选中的入库单库区必须是一样的!" ) return 1 end end -- 获取商品重量和数量累计 nRet, strRetInfo = generate_wave_detail( strLuaDEID, obj_attrs.S_NO, wave_detail_list ) if (nRet ~= 0) then lua.Error( strLuaDEID, debug.getinfo(1), "generate_wave_detail 失败!"..strRetInfo ) end table.insert( compose, item ) end if ( wh_code == '' ) then mobox.stopProgram( strLuaDEID, "入库单列表栅格中仓库列不能为空!" ) return 1 end if ( area_code == '' ) then mobox.stopProgram( strLuaDEID, "入库单列表栅格中必须有有库区列!" ) return 1 end -- 计算货品件数,种类 local total_qty = 0 local good_type_num = #wave_detail_list for n = 1, good_type_num do total_qty = total_qty + wave_detail_list[n].qty end local item_list = {} -- 需要入库的货品 local obj_attrs -- 生成要入库的货品链表 item_list for n = 1, good_type_num do local item = { item_code = wave_detail_list[n].item_code, item_name = wave_detail_list[n].item_name, row = n, volume = wave_detail_list[n].volume, weight = wave_detail_list[n].weight, cell_type = wave_detail_list[n].cell_type, qty = wave_detail_list[n].qty, alloc_qty = 0, cntr_cell_list = {}, empty_cell_type = "", upgrad_cell_index = 0, -- 标记货品开始升格的料格 A = 1, B = 2 ,如果到A还没有合适料格,要从这个料格开始降格 Q = 0, ok = false -- true 表示这个货品已经分配好入库料箱 } table.insert( item_list, item ) end -- 创建波次 local wave = m3.AllocObject(strLuaDEID,"Inbound_Wave") wave.wh_code = wh_code wave.area_code = area_code wave.station = station wave.operator_name = lua.Get_StrAttrValue( paramter.user_name ) wave.operator = lua.Get_StrAttrValue( paramter.login ) wave.good_type_num = good_type_num wave.total_qty = total_qty nRet, wave = m3.CreateDataObj( strLuaDEID, wave ) if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), '创建【入库波次】对象失败!'..wave ) end -- 创建波次组成 local strUpdateSql for n = 1, nCount do compose[n].wave_no = wave.wave_no nRet, strRetInfo = m3.CreateDataObj( strLuaDEID, compose[n] ) if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), '创建【入库波次组成】对象失败!'..strRetInfo ) end strUpdateSql = "S_WAVE_NO = '"..wave.wave_no.."', S_STATION_NO = '"..wave.station.."', S_OPERATOR_NAME = '"..wave.operator_name.."'," -- N_B_STATE = 1 表示入库单已经组盘 strUpdateSql = strUpdateSql.."S_OPERATOR = '"..wave.operator.."', N_B_STATE = 1" strCondition = "S_NO = '"..compose[n].po_no.."'" nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Inbound_Order", strCondition, strUpdateSql ) if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), "更新【入库单】信息失败!"..strRetInfo ) end end -- 创建波次明细 local wave_detail for n = 1, #wave_detail_list do wave_detail = m3.AllocObject(strLuaDEID,"IW_Detail") wave_detail.wave_no = wave.wave_no wave_detail.row_no = n wave_detail.item_code = wave_detail_list[n].item_code wave_detail.item_name = wave_detail_list[n].item_name wave_detail.cell_type = wave_detail_list[n].cell_type wave_detail.qty = wave_detail_list[n].qty wave_detail.weight = wave_detail_list[n].weight wave_detail.volume = wave_detail_list[n].volume nRet, strRetInfo = m3.CreateDataObj( strLuaDEID, wave_detail ) if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), '创建【入库波次明细】对象失败!'..strRetInfo ) end end -- 呼出空料箱算法 local ps_cntr_list = {} local ps_detail_list = {} local enable_aisle = "" -- 可用巷道 nRet, enable_aisle = prj_base.Get_Available_Lane( strLuaDEID, area_code ) if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), 'jx_base.Get_Available_Lane!'..enable_aisle ) end if ( enable_aisle == '' ) then mobox.stopProgram( strLuaDEID, "库区里的所有堆垛机状态都是不可用,无法继续呼出料箱!") return 1 end local cntr_load_capacity = wms_base.Get_nConst( strLuaDEID, "料箱最大载重" ) local ctd_code nRet, ctd_code = wms_base.Get_sConst( strLuaDEID, "WMS_Default_CNTR_Type" ) if ( nRet ~= 0 ) then lua.Stop( strLuaDEID, "系统没有定义常量 WMS_Default_CNTR_Type") ) return end if ( ctd_code == '' ) then lua.Stop( strLuaDEID, "常量 WMS_Default_CNTR_Type 的值不能为空!") ) return end -- 组织预分配料箱呼出时的配置参数 local pre_alloc_cntr_cfg = { wh_code = wh_code, area_code = area_code, station = station, aisle = enable_aisle, bs_type = "Inbound_Wave", bs_no = wave.wave_no, ctd_code = ctd_code, cntr_subtype = "", check_capacty = true, cntr_load_capacity = cntr_load_capacity, supplement = { enable = true, matching_attrs = {"S_ITEM_CODE"}, matching_order = "Last_Entry_Batch", si_cntr_num = 1 } } nRet, strRetInfo = wms_pac.Pre_Alloc_CNTR_By_CBG( strLuaDEID, item_list, pre_alloc_cntr_cfg, ps_cntr_list, ps_detail_list ) if ( nRet ~= 0 ) then if (nRet == 1) then mobox.stopProgram( strLuaDEID, strRetInfo) return 1 else lua.Error( strLuaDEID, debug.getinfo(1), "Pre_Alloc_CNTR_By_CBG 错误: "..strRetInfo) end end result = { cntr_count = #ps_cntr_list, cntr_cell_list = ps_detail_list, wave_obj_id = wave.id } mobox.returnValue( strLuaDEID, 1, lua.table2str(result) ) return 0 end